package com.omega.framework.common.util;


import org.slf4j.Logger;

import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 日志工具类
 *
 * @author Lv.
 * @date 2023/8/29 17:12
 */
public class FmkLogUtils {
    public static final String REPORT_PREFIX = "OmegaFrameworkLog ";

    public static void info(Logger log, String type, String message, Object... arguments) {
        log(LogLevel.INFO, log, type, message, null, arguments);
    }

    public static void warn(Logger log, String type, String message, Object... arguments) {
        log(LogLevel.WARN, log, type, message, null, arguments);
    }

    public static void error(Logger log, String type, String message, Object... arguments) {
        log(LogLevel.ERROR, log, type, message, null, arguments);
    }

    public static void info(Logger log, String type, String message, Throwable t) {
        log(LogLevel.INFO, log, type, message, t);
    }

    public static void warn(Logger log, String type, String message, Throwable t) {
        log(LogLevel.WARN, log, type, message, t);
    }

    public static void error(Logger log, String type, String message, Throwable t) {
        log(LogLevel.ERROR, log, type, message, t);
    }

    private static String formatMessage(String type, String message) {
        return String.format("%s %s %s", REPORT_PREFIX, type == null ? "" : type, message);
    }

    private static void log(LogLevel level, Logger log, String type, String message, Throwable t, Object... arguments) {
        String formatMessage = formatMessage(type, message);
        if (level == null) {
            level = LogLevel.WARN;
        }
        if (throttling(type)) {
            return;
        }
        if (t != null) {
            switch (level) {
                case DEBUG:
                    log.debug(formatMessage, t);
                    break;
                case INFO:
                    log.info(formatMessage, t);
                    break;
                case ERROR:
                    log.error(formatMessage, t);
                    break;
                default:
                    log.warn(formatMessage, t);
                    break;
            }
        } else {
            switch (level) {
                case DEBUG:
                    log.debug(formatMessage, arguments);
                    break;
                case INFO:
                    log.info(formatMessage, arguments);
                    break;
                case ERROR:
                    log.error(formatMessage, arguments);
                    break;
                default:
                    log.warn(formatMessage, arguments);
                    break;
            }
        }
    }

    private static volatile Map<String, AtomicInteger> logCountMap = new ConcurrentHashMap<>();

    /**
     * 每1分钟, 相同type只能打印3条日志
     *
     * @param type
     * @return
     */
    private static boolean throttling(String type) {
        if (type == null || type.isEmpty()) {
            return false;
        }
        AtomicInteger c = new AtomicInteger(0);
        AtomicInteger count = logCountMap.putIfAbsent(type, c);
        if (count == null) {
            count = c;
        }
        return count.incrementAndGet() > 3;
    }

    static {
        Timer timer = new Timer(true);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                //每分钟清空
                logCountMap = new ConcurrentHashMap<>();
            }
        }, 5000L, 60 * 1000L);
    }

    public static Map<String, AtomicInteger> getLogCountMap() {
        return logCountMap;
    }

    enum LogLevel {
        DEBUG, INFO, WARN, ERROR
    }
}
